package com.shujia

import java.io.{BufferedReader, FileReader}
import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}
import scala.io.{BufferedSource, Source, StdIn}

object Demo02Base {
  def main(args: Array[String]): Unit = {
    /**
     * Scala中的变量与常量
     * val：不可变的
     * var：可变的（可以任意赋值修改）
     */
    val i = 10 // 类型可以省略，Scala会自动推断
    val ii: Int = 10
    //    i = 100 // val 修饰的变量不可以改变

    var j = 20
    var jj: Int = 20
    j = 200

    val intArr: Array[Int] = Array[Int](1, 2, 3, 4)
    println(intArr(1))
    intArr(1) = 22
    println(intArr(1))

    /**
     * 这里val修饰的变量不可变，实际上是指变量的引用不可变
     * 能使用val的时候就尽量使用
     */

    // Scala中的数据类型
    /**
     * 所有类型都是Any的子类
     * Any有两个直接子类：AnyVal和AnyRef
     * AnyVal是任何值类型的父类
     * AnyRef是任何引用类型的父类
     *
     * 值类型：Byte、Short、Int、Long、Float、Double、Boolean、Char
     */

    val byte: Byte = 10
    val short: Short = 100
    val int: Int = 1000000
    val long: Long = 1000000000000L
    val float: Float = 1.2345678F
    val double: Double = 1.23456781011111111D

    val bool1: Boolean = true
    val bool2: Boolean = false

    val char: Char = 'a'

    // 类型的转换
    // 在Scala中需要转成什么类型，直接to对应的类型即可
    val char2int: Int = 'a' // 小转大 自动完成
    println(char2int)
    val tmpInt: Int = 98
    val int2char: Char = tmpInt.toChar // 大转小 需要手动调用
    println(int2char)

    // 字符串类型
    val str1: String = "abcdefg"
    println(str1)

    val str2: String = "12345"
    println(Integer.parseInt(str2))
    println(str2.toInt) // Scala中有很多对象的方法是通过隐式转换加上去的

    // 字符串常用的方法：substring、split、大小写转换
    val str3: String = "Java,Python|Scala"
    println(str3.substring(5, 11))
    println(str3.split(",|\\|").toList)
    // 省略形式
    // 对象在调用方法时可以省略 . 以及 括号 直接使用空格分割即可
    println(str3 split ",|\\|" toList)

    // Scala 中的运算符
    // 算术运算符
    val i1: Int = 10
    val i2: Int = 3
    println(i1 + i2)
    println(i1 - i2)
    println(i1 * i2)
    println(i1 / i2) // 注意精度
    println(i1.toDouble / i2) // 注意精度
    println(i1 % i2)

    // 比较运算符
    // Scala中直接可以使用 == 来比较两个引用变量的值相不相等 不需要使用equals
    // > >= < <= == !=
    // SQL：<>、<=>
    // SparkSQL DSL：===、=!=

    // 位运算符：<< >>
    println(8 >> 2) // 00001000 >> 2 -> 00000010
    println(2 << 2) // 00000010 << 2 -> 00001000
    println(8 & 3) // 0 00001000 00000011
    println(8 | 3) // 11 00001011

    // 逻辑运算符
    println(true && false) // 逻辑与
    println(true || false) // 逻辑或
    println(true ^ false) // 异或
    println(!false) // 取反

    println("##################################################")
    println("#" * 50)
    println("#".*(50))
    println(1.+(2))
    println(1 + 2)

    // 选择循环结构

    // 选择结构：if、else if、else
    // 输入一个年龄age，判断是否成年
    //    print("请输入一个年龄：")
    //    val age: Int = StdIn.readInt()
    val age: Int = 20
    if (age < 0 || age > 200) {
      println("年龄有误")
    } else if (age < 18) {
      println("未成年")
    } else {
      println("成年")
    }

    // 选择结构可以有返回值
    val i3: Int = 10
    val i4: Int = 5
    val i5: Int = if (i3 > i4) {
      i3
    } else {
      i4
    }

    println("return 之后的代码")

    // match 类似Java中的switch
    // 也可以返回一个值
    val p: Int = 30

    val i6: AnyVal = p match {
      case 0 =>
        println("p的值为0")
        0
      case 1 =>
        println("p的值为1")
        1
      case 2 =>
        println("p的值为2")
        2
      case 3 =>
        println("p的值为3")
        3
      case _ => // 类似Java中的default
        println("其他值")
        -1.123
    }
    println(i6)

    // 循环结构：while do、do while、for each
    // 统计1~100的和
    // while do
    var cnt: Int = 1
    var sum: Int = 0
    while (cnt <= 100) {
      sum += cnt
      cnt += 1
    }
    println(sum)
    // do while
    var cnt2: Int = 1
    var sum2: Int = 0
    do {
      sum2 += cnt2
      cnt2 += 1
    } while (cnt2 <= 100)
    println(sum2)

    // Scala中的for循环主要用于遍历集合 类似Python中的for
    // Scala中并没有fori
    val arr: Array[String] = "Hadoop,Hive,HBase".split(",")
    println(arr)
    for (s: String <- arr) {
      println(s)
    }
    // Scala中函数式编程的写法
    arr.foreach(println)

    // 如果非得使用下标遍历元素 可以使用for 结合 to、until、range进行遍历

    for (i <- 0 to arr.length - 1) {
      println(arr(i))
    }

    for (i <- 0 until arr.length) {
      println(arr(i))
    }

    for (i <- Range(0, arr.length, 1)) {
      println(arr(i))
    }

    // Scala中常见的操作：读写文件、操作MySQL

    // 读文件

    // Java的方式
    val br: BufferedReader = new BufferedReader(new FileReader("scala/data/stu/students.txt"))
    var line: String = br.readLine()
    while (line != null) {
      println(line)
      line = br.readLine()
    }
    println("$" * 50)
    // Scala的方式
    val bs: BufferedSource = Source
      .fromFile("scala/data/stu/students.txt")

    val iter: Iterator[String] = bs.getLines()
    for (elem <- iter) {
      println(elem)
    }
    println("#" * 50)
    // 链式调用
    Source
      .fromFile("scala/data/stu/students.txt")
      .getLines()
      .foreach(println)

    // Scala写文件没有特殊的方式，使用Java的那一套即可

    // 读取MySQL中的数据：实际上也没有特殊的方式，也是使用Java的那一套
    // 建立连接
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://rm-bp1h7v927zia3t8iwho.mysql.rds.aliyuncs.com:3307/stu025", "stu025", "123456")

    val clazz: String = "文科一班"

    val sql1: String = "select id,name,age,gender from students where clazz = ?"
    // Scala中有一种特殊的方式可以让SQL换行
    val sql2: String =
      """
        |select id
        |       ,name
        |       ,age
        |       ,gender
        |from students
        |where clazz = ?
        |""".stripMargin
    // 创建statement
    val pSt: PreparedStatement = conn.prepareStatement(sql2)



    // 设置参数
    pSt.setString(1, clazz)

    // 执行查询
    val rs: ResultSet = pSt.executeQuery()

    // 遍历获取数据
    while (rs.next()) {
      val id: Int = rs.getInt("id")
      val name: String = rs.getString("name")
      val age: Int = rs.getInt("age")
      val gender: String = rs.getString("gender")
      val _clazz: String = "文科一班"

      //      println(id + "," + name + "," + age + "," + gender)
      // Scala格式化字符串
      println(s"$id,$name,$age,$gender,${_clazz}")


    }

    // 关闭连接
    rs.close()
    pSt.close()
    conn.close()




  }

}
